package com.zahb.qadx.net;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;

/**
 * Created by Zdw on 2020/10/20 16:18
 */
public final class CustomTypeAdapterFactory implements TypeAdapterFactory {

    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        Class<T> rawType = (Class<T>) type.getRawType();
        if (rawType == String.class)
            return (TypeAdapter<T>) new StringTypeAdapter();
        if (rawType == Boolean.class || rawType == boolean.class)
            return (TypeAdapter<T>) new BooleanTypeAdapter();
        if (rawType == Integer.class || rawType == int.class)
            return (TypeAdapter<T>) new IntegerTypeAdapter();
        if (rawType == Long.class || rawType == long.class)
            return (TypeAdapter<T>) new LongTypeAdapter();
        if (rawType == Float.class || rawType == float.class)
            return (TypeAdapter<T>) new FloatTypeAdapter();
        if (rawType == Double.class || rawType == double.class)
            return (TypeAdapter<T>) new DoubleTypeAdapter();
        return null;
    }

    public static class StringTypeAdapter extends TypeAdapter<String> {

        @Override
        public void write(JsonWriter out, String value) throws IOException {
            out.value(value);
        }

        @Override
        public String read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                return "";
            } else if (in.peek() == JsonToken.STRING) {
                String value = in.nextString();
                if ("null".equals(value)) {
                    return "";
                } else {
                    return value;
                }
            }
            return in.nextString();
        }
    }

    public static class BooleanTypeAdapter extends TypeAdapter<Boolean> {

        @Override
        public void write(JsonWriter out, Boolean value) throws IOException {
            out.value(value);
        }

        @Override
        public Boolean read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                return false;
            } else if (in.peek() == JsonToken.STRING) {
                String value = in.nextString();
                return Boolean.parseBoolean(value);
            } else if (in.peek() == JsonToken.NUMBER) {
                in.nextDouble();//使用double来接，避免出错
                return false;
            }
            return in.nextBoolean();
        }
    }

    public static class IntegerTypeAdapter extends TypeAdapter<Integer> {

        @Override
        public void write(JsonWriter out, Integer value) throws IOException {
            out.value(value);
        }

        @Override
        public Integer read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                return -1;
            } else if (in.peek() == JsonToken.STRING) {
                String value = in.nextString();
                try {
                    return Integer.parseInt(value);
                } catch (NumberFormatException e) {
                    return -1;
                }
            } else if (in.peek() == JsonToken.BOOLEAN) {
                in.nextBoolean();
                return -1;
            }
            return in.nextInt();
        }
    }

    public static class LongTypeAdapter extends TypeAdapter<Long> {

        @Override
        public void write(JsonWriter out, Long value) throws IOException {
            out.value(value);
        }

        @Override
        public Long read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                return -1L;
            } else if (in.peek() == JsonToken.STRING) {
                String value = in.nextString();
                try {
                    return Long.parseLong(value);
                } catch (NumberFormatException e) {
                    return -1L;
                }
            } else if (in.peek() == JsonToken.BOOLEAN) {
                in.nextBoolean();
                return -1L;
            }
            return in.nextLong();
        }
    }

    public static class FloatTypeAdapter extends TypeAdapter<Float> {

        @Override
        public void write(JsonWriter out, Float value) throws IOException {
            out.value(value);
        }

        @Override
        public Float read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                return -1f;
            } else if (in.peek() == JsonToken.STRING) {
                String value = in.nextString();
                try {
                    return Float.parseFloat(value);
                } catch (NumberFormatException e) {
                    return -1f;
                }
            } else if (in.peek() == JsonToken.BOOLEAN) {
                in.nextBoolean();
                return -1f;
            }
            return (float) in.nextDouble();
        }
    }

    public static class DoubleTypeAdapter extends TypeAdapter<Double> {

        @Override
        public void write(JsonWriter out, Double value) throws IOException {
            out.value(value);
        }

        @Override
        public Double read(JsonReader in) throws IOException {
            if (in.peek() == JsonToken.NULL) {
                in.nextNull();
                return -1d;
            } else if (in.peek() == JsonToken.STRING) {
                String value = in.nextString();
                try {
                    return Double.parseDouble(value);
                } catch (NumberFormatException e) {
                    return -1d;
                }
            } else if (in.peek() == JsonToken.BOOLEAN) {
                in.nextBoolean();
                return -1d;
            }
            return in.nextDouble();
        }
    }
}
